require "revision"

class Mercurial
  include CommandLine
  
  attr_accessor :url, :username, :password
  
  def initialize(options = {}, parser = MercurialLogParser.new)
    @parser = parser
    @url, @username, @password, @interactive = 
          options.delete(:url), options.delete(:username), options.delete(:password), options.delete(:interactive)
    raise "don't know how to handle '#{options.keys.first}'" if options.length > 0
  end
  
  def checkout(target_directory, revision = nil) 
    @url or raise 'URL not specified'

    options = "#{@url} #{target_directory}"
    #options << " --username #{@username}" if username
    #options << " --password #{@password}" if password
    options << " --rev #{revision_number(revision)}" if revision

    # need to read from command output, because otherwise tests break
    execute(self.clone_command << " " << options) { |io| io.readlines }
 end
  
  def latest_revision(project) 
    Dir.chdir(project.local_checkout) do
      self.execute(self.pull_command)
      @parser.parse_log(execute(self.log_command("tip"))).first
    end
  end
  
  def revisions_since(project, revision_number)
    Dir.chdir(project.local_checkout) do
      self.execute(self.pull_command)
      revs = @parser.parse_log(self.execute(self.log_command(revision_number)))
      revs.delete_if do |rev|
        rev.number == revision_number
      end
      revs
    end    
  end
  
  def update(project, revision) 
    Dir.chdir(project.local_checkout) do
      self.execute(self.pull_command)
      self.execute(self.update_command(revision))
    end
  end
  
  def pull_command
    "hg pull"
  end
  
  def clone_command
    "hg clone"
  end
  
  def update_command(revision=nil)
    command = "hg update"
    command << " #{revision.number}" unless revision.nil?
    command
  end
  
  def revision_number(revision)
    revision.respond_to?(:number) ? revision.number : revision.to_i
  end

  def log_command(revision_number="tip")
    "hg log -v -r tip:#{revision_number}"
  end
  
  protected
  
  def execute(command)
    `#{command}`    
  end
end
